﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Co9320.NamaAlert.Model
{
	internal enum TokenType
	{
		NotAvailable,
		String,
		LeftBracket,
		RightBracket,
		LineBreak,
		EOF
	}

	internal class Token
	{
		public Token(string Value, TokenType Type)
		{
			this.Value = Value;
			this.Type = Type;
		}

		public string Value
		{
			get;
			private set;
		}

		public TokenType Type
		{
			get;
			private set;
		}
	}

	/// <summary>
	/// Content Lexer stream
	/// </summary>
	internal class Lexer
	{
		private class CharacterStream
		{
			private char[] Source;
			private int CurrentIndex;

			public CharacterStream(string Source)
			{
				if (Source != null)
				{
					this.Source = Source.ToCharArray();
				}
				else
				{
					this.Source = "".ToCharArray();
				}
				CurrentIndex = -1;
			}

			public bool Next()
			{
				if (++CurrentIndex > Source.Length)
				{
					CurrentIndex = Source.Length;
					return false;
				}
				else
				{
					return true;
				}
			}

			public char Value
			{
				get
				{
					if (CurrentIndex < Source.Length)
					{
						return Source[CurrentIndex];
					}
					else
					{
						return (char)0;
					}
				}
			}

			public char Peek()
			{
				int PeekIdx = CurrentIndex + 1;

				if (PeekIdx < Source.Length)
				{
					return Source[PeekIdx];
				}
				else
				{
					return (char)0;
				}
			}
		}

		CharacterStream str;
		LinkedList<Token> TokenList;
		LinkedListNode<Token> Current_;

		public Lexer(string Source)
		{
			str = new CharacterStream(Source);
			TokenList = new LinkedList<Token>();
			BuildList();
			Current_ = TokenList.First;
		}

		private void BuildList()
		{
			Token token;

			TokenList.AddLast((Token)null);

			while ((token = GetToken()) != null)
			{
				TokenList.AddLast(token);
			}
		}

		private Token GetToken()
		{
			while (str.Next())
			{
				char current = str.Value;

				if (current == '】')
				{
					return new Token(current.ToString(), TokenType.RightBracket);
				}
                else if (current == '【')
				{
					return new Token(current.ToString(), TokenType.LeftBracket);
				}
				else if (current == '\r')
				{
					if (str.Peek() == '\n')
					{
						str.Next();
						return new Token("\r\n", TokenType.LineBreak);
					}
					else
					{
						return new Token(current.ToString(), TokenType.LineBreak);
					}
				}
				else if (current == '\n')
				{
					return new Token(current.ToString(), TokenType.LineBreak);
				}
				else if (current == (char)0)
				{
					return new Token(null, TokenType.EOF);
				}
				else
				{
					return new Token(GetString(), TokenType.String);
				}
			}

			return null;
		}

		private string GetString()
		{
			StringBuilder bld = new StringBuilder();

			for (; ; )
			{
				bld.Append(str.Value);

                if (str.Peek() == '】' || str.Peek() == '【' || str.Peek() == (char)0 || str.Peek() == '\r' || str.Peek() == '\n')
				{
					break;
				}
				else
				{
					str.Next();
				}
			}

			return bld.ToString();
		}

		public Token Current
		{
			get
			{
				return Current_.Value;
			}
		}

		public Token Peek
		{
			get
			{
				return Current_.Next.Value;
			}
		}

		public bool Next()
		{
			if (Current_.Next == null)
			{
				return false;
			}

			if (Current_.Next.Value.Type != TokenType.EOF)
			{
				Current_ = Current_.Next;
				return true;
			}
			else
			{
				Current_ = Current_.Next;
				return false;
			}
		}


	}
}
